#!/usr/bin/env perl

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}' if 0;

use strict;
use warnings;

use FindBin;
use File::Find;
use Getopt::Long;
use Pod::Usage;
use IO::Dir;

my $help    = 0;
my $verbose = 0;
my $reload  = 0;

my %opt = (
    'help|?'     => \$help,
    'verbose|v!' => \$verbose,
    'reload|r'   => \$reload,
);
GetOptions(%opt);

pod2usage(1) if $help;

sub do_build {
    # build cmake command
    my $command = "cmake .. -DCMAKE_BUILD_TYPE=Debug";

    # check build directory
    my $build_dir = "$FindBin::Bin/../build";
    unless (-e $build_dir) {
        mkdir($build_dir, 0755) or die $!;
    }
    chdir $build_dir or die $!;
    print $command, "\n";
    system($command);
    print "make\n";
    system("make");

    if ($verbose) {
        my @tests = ();
        my $tests_dir = IO::Dir->new('tests');
        while (defined(my $filename = $tests_dir->read)) {
            next if (-d $filename);
            next if ($filename =~ /\.cmake$/);
            next if ($filename eq 'Makefile');
            push(@tests, $filename);
        }
        for my $test ( @tests ) {
            my $test_command = sprintf("./tests/%s", $test);
            print $test_command, "\n";
            system(sprintf($test_command));
        }
    } else {
        print "make test\n";
        system("make test");
    }
}

&do_build();
exit unless $reload;

my %FILES = ();
&find_updated_files();

print "1. Waiting for source changes... (press Ctrl+C to interrupt)\n";
my $build_count = 1;

while (1) {
    sleep 1;
    if (&find_updated_files()) {
        print "found updated file\n";
        print "start to build\n";
        &do_build();
        $build_count++;
        print sprintf("%d. Waiting for source changes... (press Ctrl+C to interrupt)\n", $build_count);
    }
}

sub find_updated_files {
    my $found = 0;
    for my $type (qw(include src tests)) {
        my $dir = "$FindBin::Bin/../" . $type;
        File::Find::find({ no_chdir => 1, wanted => sub {
            my $filepath = $File::Find::name; 
            return unless -f $filepath;
            my $last_update = (stat($filepath))[9];

            unless (exists $FILES{$filepath}) {
                $found = 1;
                $FILES{$filepath} = $last_update;
            } else {
                if ($FILES{$filepath} != $last_update) {
                    $found = 1;
                    $FILES{$filepath} = $last_update;
                }
            }
        } }, $dir);
    }
    return $found;
}


1;
__END__
=head1 NAME

test - This program helps your building and testing workaround.

=head1 SYNOPSIS

    test [options]

Example:

    ./scripts/test --verbose
    ./scripts/test --reload
    ./scripts/test -v -r

Options:

    -verbose (v) if this flag is on, print verbose results of google-tests. If not, the test results would be compressed.
    -reload  (r) if this flag is on, automatically find updated files, and build them, repeatedly.

=head1 DESCRIPTION

This helps your building and testing workaround.

=head1 AUTHOR

Lyo Kato, E<lt>lyo.kato@gmail.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright 2010 Lyo Kato. All rights reserved.

This library is free software. You can redistribute it and/or modify it under
the same terms as perl itself.

=cut

